package com.autumn.config.services.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.autumn.config.api.dto.output.ConnectionConfigureOutput;
import com.autumn.config.api.services.ICacheService;
import com.autumn.config.api.vo.*;
import com.autumn.config.consts.RedisKeyConsts;
import com.autumn.redis.AutumnRedisTemplate;
import com.autumn.util.StringUtils;
import com.autumn.util.function.FunctionOneResult;
import com.autumn.util.function.FunctionTwoResult;
import com.autumn.util.json.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 缓存服务
 * 
 * @author 老码农
 *
 *         2018-01-04 16:16:00
 */
@Service(interfaceClass = ICacheService.class)
@Component
public class CacheServiceImpl implements ICacheService {

	@Autowired
	private AutumnRedisTemplate redisTemplate;

	private String getServiceConnectionListKey(String serviceId) {
		return RedisKeyConsts.Application.SERVICE_CONNECTION_LIST_PREFIX + serviceId.toUpperCase();
	}

	private String getServiceConnectionKey(String serviceId, String identity) {
		return String.format("%s%s_%s", RedisKeyConsts.Application.SERVICE_CONNECTION_LIST_PREFIX,
				serviceId.toUpperCase(), identity.toUpperCase());
	}

	private String getServiceInfoKey(String serviceId) {
		return RedisKeyConsts.Application.SERVICE_INFO_PREFIX + serviceId.toUpperCase();
	}

	private String getServiceDataSourceKey(ServiceDataSourceValue input) {
		return RedisKeyConsts.Application.SERVICE_DATA_SOURCE_PREFIX
				+ String.format("%s_%s_%s", input.getServiceId().toUpperCase(),
						input.getTargetServiceId().toUpperCase(), input.getConnectionType().toString());
	}

	private String getConnectionKey(String name) {
		return RedisKeyConsts.Connection.CONN_INFO_PREFIX + name.toUpperCase();
	}

	private String getServiceProfileKey(ServiceProfileValue input) {
		String label = input.getLabel();
		if (StringUtils.isNullOrBlank(label)) {
			label = "";
		}
		return String.format("%s%s_%s_%s", RedisKeyConsts.Application.SERVICE_PROFILE_PREFIX,
				input.getServiceId().trim().toUpperCase(), input.getProfile().trim().toUpperCase(),
				label.trim().toUpperCase());
	}

	@Override
	public ApplicationInfoValue getServiceQueryById(String serviceId) {
		String key = getServiceInfoKey(serviceId);
		return redisTemplate.get(key, ApplicationInfoValue.class);
	}

	@Override
	public ApplicationInfoValue getServiceQueryById(String serviceId,
			FunctionOneResult<String, ApplicationInfoValue> fun) {
		ApplicationInfoValue result = getServiceQueryById(serviceId);
		if (result == null && fun != null) {
			result = fun.apply(serviceId);
			if (result != null) {
				String key = getServiceInfoKey(serviceId);
				redisTemplate.set(key, result);
			}
		}
		return result;
	}

	@Override
	public ServiceDataSourceConfigureValue getServiceTargetDataSource(ServiceDataSourceValue input) {
		String key = getServiceDataSourceKey(input);
		return redisTemplate.get(key, ServiceDataSourceConfigureValue.class);
	}

	@Override
	public ServiceDataSourceConfigureValue getServiceTargetDataSource(ServiceDataSourceValue input,
			FunctionOneResult<ServiceDataSourceValue, ServiceDataSourceConfigureValue> fun) {
		ServiceDataSourceConfigureValue result = getServiceTargetDataSource(input);
		if (result == null && fun != null) {
			result = fun.apply(input);
			if (result != null) {
				String key = getServiceDataSourceKey(input);
				redisTemplate.set(key, result);
			}
		}
		return result;
	}

	@Override
	public List<ServiceConnectionConfigureValue> getServiceConnectionList(String serviceId) {
		String key = getServiceConnectionListKey(serviceId);
		String json = redisTemplate.getString(key);
		if (StringUtils.isNullOrBlank(json)) {
			return null;
		}
		return JsonUtils.parseList(json, ServiceConnectionConfigureValue.class);
	}

	@Override
	public List<ServiceConnectionConfigureValue> getServiceConnectionList(String serviceId,
			FunctionOneResult<String, List<ServiceConnectionConfigureValue>> fun) {
		List<ServiceConnectionConfigureValue> items = getServiceConnectionList(serviceId);
		if (items == null && fun != null) {
			items = fun.apply(serviceId);
			if (items != null && items.size() > 0) {
				String key = getServiceConnectionListKey(serviceId);
				redisTemplate.set(key, JsonUtils.toJSONString(items));
			}
		}
		return items;
	}

	@Override
	public ServiceConnectionConfigureValue getServiceConnection(String serviceId, String identity) {
		String key = getServiceConnectionKey(serviceId, identity);
		String json = redisTemplate.getString(key);
		if (StringUtils.isNullOrBlank(json)) {
			return null;
		}
		return JsonUtils.parseObject(json, ServiceConnectionConfigureValue.class);
	}

	@Override
	public ServiceConnectionConfigureValue getServiceConnection(String serviceId, String identity,
			FunctionTwoResult<String, String, ServiceConnectionConfigureValue> fun) {
		ServiceConnectionConfigureValue result = getServiceConnection(serviceId, identity);
		if (result == null && fun != null) {
			result = fun.apply(serviceId, identity);
			if (result != null) {
				String key = getServiceConnectionKey(serviceId, identity);
				redisTemplate.set(key, result);
			}
		}
		return result;
	}

	@Override
	public ServiceProfileInfo getServiceProfile(ServiceProfileValue input) {
		String key = getServiceProfileKey(input);
		String json = redisTemplate.getString(key);
		if (StringUtils.isNullOrBlank(json)) {
			return null;
		}
		return JsonUtils.parseObject(json, ServiceProfileInfo.class);
	}

	@Override
	public ServiceProfileInfo getServiceProfile(ServiceProfileValue input,
			FunctionOneResult<ServiceProfileValue, ServiceProfileInfo> fun) {
		ServiceProfileInfo result = this.getServiceProfile(input);
		if (result == null && fun != null) {
			result = fun.apply(input);
			if (result != null) {
				String key = getServiceProfileKey(input);
				redisTemplate.set(key, result);
			}
		}
		return result;
	}

	@Override
	public ConnectionConfigureOutput getConnectionInfo(String name) {
		String key = getConnectionKey(name);
		return redisTemplate.get(key, ConnectionConfigureOutput.class);
	}

	@Override
	public ConnectionConfigureOutput getConnectionInfo(String name,
			FunctionOneResult<String, ConnectionConfigureOutput> fun) {
		ConnectionConfigureOutput result = getConnectionInfo(name);
		if (result == null && fun != null) {
			result = fun.apply(name);
			if (result != null) {
				String key = getConnectionKey(name);
				redisTemplate.set(key, result);
			}
		}
		return result;
	}

	@Override
	public void deleteServiceInfo(String serviceId) {
		List<String> keys = new ArrayList<>();
		keys.add(getServiceConnectionListKey(serviceId));
		keys.add(getServiceInfoKey(serviceId));
		redisTemplate.delete(keys);
		redisTemplate.deleteByMatches(
				RedisKeyConsts.Application.SERVICE_CONNECTION_LIST_PREFIX + serviceId.toUpperCase() + "_*");
		redisTemplate.deleteByMatches(
				RedisKeyConsts.Application.SERVICE_DATA_SOURCE_PREFIX + serviceId.toUpperCase() + "_*");
		redisTemplate
				.deleteByMatches(RedisKeyConsts.Application.SERVICE_PROFILE_PREFIX + serviceId.toUpperCase() + "_*");
	}

	/**
	 * 删除服务配置
	 * 
	 * @param serviceId
	 *            服务id
	 *
	 */
	@Override
	public void deleteServiceProfile(String serviceId) {
		redisTemplate
				.deleteByMatches(RedisKeyConsts.Application.SERVICE_PROFILE_PREFIX + serviceId.toUpperCase() + "_*");
	}

	@Override
	public void deleteALLServiceInfo() {
		redisTemplate.deleteByMatches(RedisKeyConsts.Application.APP_PREFIX + "*");
	}

	@Override
	public void deleteConnectionInfo(String name) {
		List<String> keys = new ArrayList<>();
		keys.add(getConnectionKey(name));
		redisTemplate.delete(keys);
	}

	@Override
	public void deleteALLConnectionInfo() {
		redisTemplate.deleteByMatches(RedisKeyConsts.Connection.CONN_PREFIX + "*");
	}

}
